package com.n1global.serveranalytics;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.n1global.acc.CouchDbConfig;
import com.ning.http.client.AsyncHttpClient;

public class EventLogger {
    private LinkedBlockingQueue<LogMessage> messages = new LinkedBlockingQueue<>();

    private final int MAX_CAPACITY = 1000;

    private LogDb logDb;

    private volatile long lastFlush;

    public EventLogger(String serverUrl, String dbName, String user, String password, AsyncHttpClient httpClient) {
        logDb = new LogDb(new CouchDbConfig.Builder().setDbName(dbName).setServerUrl(serverUrl).setUser(user).setPassword(password).build(), httpClient);

        new Thread() {
            @Override
            public void run() {
                while (!interrupted()) {
                    if ((System.currentTimeMillis() - lastFlush > TimeUnit.SECONDS.toMillis(3)) || messages.size() > MAX_CAPACITY) {
                        flush();
                    }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        interrupt();
                    }
                }
            };
        }.start();
    }

    public void exception(Throwable e, String... fields) {
        exception(e, null, fields);
    }

    public void exception(Throwable e, Object payload, String... fields) {
        ExceptionPayload ep = new ExceptionPayload();

        ep.processException(e, payload);

        String[] arr = new String[fields.length + 1];

        System.arraycopy(fields, 0, arr, 1, fields.length);

        arr[0] = "Exception";

        count(1, ep, arr);
    }

    public void instant(Object value, String... fields) {
        count(1, value, fields);
    }

    public void message(Object message, String... fields) {
        String[] arr = new String[fields.length + 1];

        System.arraycopy(fields, 0, arr, 1, fields.length);

        arr[0] = "Message";

        count(1, message, arr);
    }

    public void count(long count, String... fields) {
        count(count, null, fields);
    }

    public void count(long count, Object payload, String... fields) {
        messages.add(new LogMessage(count, payload, fields));
    }

    public void flush() {
        List<LogMessage> list = new ArrayList<>();

        messages.drainTo(list);

        if (!list.isEmpty()) {
            logDb.bulk(list);

            logDb.getByDateView().createMapQuery().limit(1).async().asId();
            logDb.getByFieldsView().createMapQuery().limit(1).async().asId();
        }

        lastFlush = System.currentTimeMillis();
    }

    public LogDb getLogDb() {
        return logDb;
    }
}
